home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / tde3.zip / WORDWRAP.C < prev   
C/C++ Source or Header  |  1993-06-05  |  30KB  |  978 lines

  1. /*
  2.  * This module contains the word wrap and format paragraph functions.  The
  3.  *  right_justify( ) function is based on the spread function in _Software
  4.  *  Tools_ by Brian Kernighan and P J Plauger.  My version of the spread
  5.  *  function handles lines with extra blanks in the text, e.g. two blanks
  6.  *  after periods.  All of the other word processing routines are original
  7.  *  and written by me, Frank, and are not guaranteed to work as designed.
  8.  *
  9.  * See:
  10.  *
  11.  *   Brian W. Kernighan and P. J. Plauger, _Software Tools_, Addison-
  12.  *    Wesly, Reading, Mass., 1976, Section 7.7, "Right Margin Justification",
  13.  *    pp 239-242.  ISBN 0-201-03669-X.
  14.  *
  15.  * Note: right margin justification was added in TDE 2.2.
  16.  *
  17.  * New editor name:  TDE, the Thomson-Davis Editor.
  18.  * Author:           Frank Davis
  19.  * Date:             June 5, 1991, version 1.0
  20.  * Date:             July 29, 1991, version 1.1
  21.  * Date:             October 5, 1991, version 1.2
  22.  * Date:             January 20, 1992, version 1.3
  23.  * Date:             February 17, 1992, version 1.4
  24.  * Date:             April 1, 1992, version 1.5
  25.  * Date:             June 5, 1992, version 2.0
  26.  * Date:             October 31, 1992, version 2.1
  27.  * Date:             April 1, 1993, version 2.2
  28.  * Date:             June 5, 1993, version 3.0
  29.  *
  30.  * This code is released into the public domain, Frank Davis.
  31.  * You may distribute it freely.
  32.  */
  33.  
  34. #include "tdestr.h"     /* global variables definitions */
  35. #include "common.h"     /* external global variable declarations */
  36. #include "define.h"
  37. #include "tdefunc.h"
  38.  
  39.  
  40. /*
  41.  * Name:    find_left_margin
  42.  * Purpose: find left margin depending on word wrap mode
  43.  * Date:    June 5, 1992
  44.  * Passed:  ll:         node pointer to current line
  45.  *          wrap_mode:  current word wrap mode
  46.  * Notes:   the algorithm used to figure the indent column was yanked out
  47.  *           of the insert_newline( ) function and was made into a more
  48.  *           general algorithm for figuring the left margin irregardless
  49.  *           of word wrap or indent mode.  when in the DYNAMIC_WRAP mode,
  50.  *           the user don't have to keep changing the left margin when
  51.  *           special indentation is needed.
  52.  */
  53. int  find_left_margin( line_list_ptr ll, int wrap_mode )
  54. {
  55. register int lm;
  56. int  len;
  57. text_ptr source;
  58.  
  59.    if (wrap_mode == FIXED_WRAP) {
  60.       /*
  61.        * for FIXED_WRAP mode, the left and paragraph margins are determined
  62.        *   from the master mode structure.
  63.        */
  64.       if (g_status.copied) {
  65.          source = (text_ptr)g_status.line_buff;
  66.          len    = g_status.line_buff_len;
  67.       } else {
  68.          if (ll->prev != NULL) {
  69.             source = ll->prev->line;
  70.             len    = ll->prev->len;
  71.          } else {
  72.             source = NULL;
  73.             len    = 0;
  74.          }
  75.       }
  76.       if (source == NULL)
  77.          lm = mode.parg_margin;
  78.       else if (find_end( source, len ) == 0)
  79.          lm = mode.parg_margin;
  80.       else
  81.          lm = mode.left_margin;
  82.    } else {
  83.       /*
  84.        * for Indent and DYNAMIC_WRAP modes, the left margin is determined
  85.        *  from the first non blank line above the cursor.
  86.        */
  87.       if (g_status.copied == TRUE) {
  88.          source = (text_ptr)g_status.line_buff;
  89.          len    = g_status.line_buff_len;
  90.       } else {
  91.          source = ll->line;
  92.          len    = ll->len;
  93.       }
  94.       lm = first_non_blank( source, len );
  95.       if (is_line_blank( source, len ) && ll->prev != NULL) {
  96.          for (ll=ll->prev; ll != NULL; ll=ll->prev) {
  97.             lm = first_non_blank( ll->line, ll->len );
  98.             if (!is_line_blank( ll->line, ll->len ))
  99.                break;
  100.          }
  101.       }
  102.    }
  103.    return( lm );
  104. }
  105.  
  106.  
  107. /*
  108.  * Name:    word_wrap
  109.  * Purpose: make sure lines don't get longer than right margin
  110.  * Date:    November 27, 1991
  111.  * Passed:  window:  pointer to current window
  112.  * Notes:   rcol, lm, rm, pm all start counting at zero.
  113.  *          len (line length) starts counting at 1.
  114.  *
  115.  *          when we compare margins and line lengths, we either have to
  116.  *          add one to the margins or subtract one from the len.  I add
  117.  *          one to the margins.
  118.  */
  119. void word_wrap( WINDOW *window )
  120. {
  121. int  c;                 /* character the user just entered. */
  122. register int len;       /* length of current line */
  123. int  i;                 /* padding spaces required */
  124. line_list_ptr p;        /* line above wrapped line */
  125. int  rcol;
  126. int  lm;
  127. int  rm;
  128. int  side;
  129. register WINDOW *win;          /* put window pointer in a register */
  130.  
  131.    win = window;
  132.  
  133.    /*
  134.     * set up a few local variables.
  135.     */
  136.    c = g_status.key_pressed;
  137.    rcol = win->rcol;
  138.    copy_line( win->ll );
  139.    detab_linebuff( );
  140.  
  141.    /*
  142.     * always start the right margin justification on the right side
  143.     *  at the beginning of paragraphs.  then, alternate with left margin.
  144.     */
  145.    side = 1;
  146.    p = win->ll->prev;
  147.    while (p != NULL  &&  !is_line_blank( p->line, p->len )) {
  148.       ++side;
  149.       p = p->prev;
  150.    }
  151.    side = (side & 1) ? RIGHT : LEFT;
  152.  
  153.  
  154.    /*
  155.     * when we wrap, we need know where the left margin is.
  156.     * let's look at the line above to see if this is the first line
  157.     * in a paragraph.
  158.     */
  159.    p = win->ll->prev;
  160.  
  161.    lm = find_left_margin( win->ll, mode.word_wrap );
  162.    rm = mode.right_margin;
  163.  
  164.    /*
  165.     * there two ways that words are pushed onto next line.
  166.     *  1. if the word being typed goes over the right margin
  167.     *  2. typing a word in the middle of the line pushes words at end of
  168.     *     line to next line
  169.     *
  170.     * if the user enters spaces past the right margin then we don't
  171.     *  word wrap spaces.
  172.     */
  173.    len = g_status.line_buff_len;
  174.    if (rcol > rm+1 && c != ' ') {
  175.  
  176.       /*
  177.        * if this is the first line in a paragraph then set left margin
  178.        *  to paragraph margin.
  179.        */
  180.       if ((p == NULL || is_line_blank( p->line, p->len )) &&
  181.            first_non_blank( (text_ptr)g_status.line_buff,
  182.                  g_status.line_buff_len ) > rm && mode.word_wrap == FIXED_WRAP)
  183.          lm = mode.parg_margin;
  184.  
  185.       /*
  186.        * simple word wrap.  the cursor goes past the right margin.
  187.        *  find the beginning of the word and put it on a new line.
  188.        *
  189.        * Special case - if the word begins at the left margin then
  190.        *  don't wrap it.
  191.        */
  192.       for (i=rcol-1; i > lm  &&  g_status.line_buff[i] != ' '; )
  193.          i--;
  194.       if (i > lm) {
  195.          i++;
  196.          win->rcol = i;
  197.          g_status.command = WordWrap;
  198.          insert_newline( win );
  199.          if (mode.right_justify == TRUE)
  200.             justify_right_margin( win, win->ll->prev,
  201.                  mode.word_wrap == FIXED_WRAP ? find_left_margin( win->ll->prev,
  202.                  mode.word_wrap ) : lm, rm, side );
  203.  
  204.          /*
  205.           * find out where to place the cursor on the new line.
  206.           */
  207.          win->rcol = lm + rcol - i;
  208.          check_virtual_col( win, win->rcol, win->rcol );
  209.  
  210.          /*
  211.           * we just wrapped the word at the eol.  now, let's see if
  212.           *  we can combine it with the line below.  since just added
  213.           *  a line, set new_line to false - don't add another line.
  214.           */
  215.  
  216.          len = find_end( win->ll->line, win->ll->len );
  217.          if (len < rm+1)
  218.             combine_wrap_spill( win, len, lm, rm, side, FALSE );
  219.       }
  220.    } else if (len > rm+1) {
  221.  
  222.       /*
  223.        * this is the second word wrap case.  we are pushing words onto
  224.        * next line.  we need to now what character is in the right margin.
  225.        *
  226.        * 1) if the character is not a space, then we need to search backwards
  227.        *    to find the start of the word that is on the right margin.
  228.        * 2) if the character is a space, then we need to search forward to
  229.        *    find the word that is over the right margin.
  230.        */
  231.  
  232.       /*
  233.        * don't wrap spaces past right margin
  234.        */
  235.       if (c == ' ' && rcol > rm) {
  236.          for (i=rcol; i<len && g_status.line_buff[i] == ' ';)
  237.             i++;
  238.  
  239.          /*
  240.           * if i == len then all that's left on line is blanks - don't wrap.
  241.           */
  242.          if (i < len)
  243.             combine_wrap_spill( win, i, lm, rm, side, TRUE );
  244.  
  245.       } else if (g_status.line_buff[rm+1] != ' ') {
  246.  
  247.          /*
  248.           * search backwards for the word to put on next line.
  249.           */
  250.          for (i=rm+1; i > lm  &&  g_status.line_buff[i] != ' '; )
  251.             i--;
  252.  
  253.          /*
  254.           * if we search all the way back to left margin then test for
  255.           * a special case - see the matching else for more info.
  256.           */
  257.          if (i > lm) {
  258.             i++;
  259.  
  260.             /*
  261.              * if i > rcol then cursor stays on same line.
  262.              */
  263.             if (i > rcol) {
  264.                combine_wrap_spill( win, i, lm, rm, side, TRUE );
  265.  
  266.             /*
  267.              * split the line at or behind the cursor.  almost the
  268.              *  same as when the cursor goes over the right margin.
  269.              */
  270.             } else if (i <= rcol) {
  271.                win->rcol = i;
  272.                g_status.command = WordWrap;
  273.                insert_newline( win );
  274.                if (mode.right_justify == TRUE)
  275.                   justify_right_margin( win, win->ll->prev,
  276.                    mode.word_wrap == FIXED_WRAP ?
  277.                    find_left_margin( win->ll->prev, mode.word_wrap ) : lm,
  278.                    rm, side );
  279.                win->rcol = lm + rcol - i;
  280.                check_virtual_col( win, win->rcol, win->rcol );
  281.                len = find_end( win->ll->line, win->ll->len );
  282.                if (len < rm+1)
  283.                   combine_wrap_spill( win, len, lm, rm, side, FALSE );
  284.             }
  285.          }
  286.  
  287.          /*
  288.           * if the user changed margins or for some reason there's a long
  289.           *  text line, let's see if there are any words past the right
  290.           *  margin.  if we get to this else, we know the current word
  291.           *  begins at least at the left margin.
  292.           *
  293.           * now search forwards for a break
  294.           */
  295.       } else {
  296.  
  297.          /*
  298.           * go to the right margin and see if there are any words past
  299.           *  right margin.
  300.           */
  301.          for (i=rm+1; i<len && g_status.line_buff[i] == ' '; )
  302.             i++;
  303.  
  304.          /*
  305.           * we either found a space or the eol.  test for eol.
  306.           * if i == len then this is one big word - don't wrap it.
  307.           */
  308.          if (i != len)
  309.             combine_wrap_spill( win, i, lm, rm, side, TRUE );
  310.       }
  311.    }
  312. }
  313.  
  314.  
  315. /*
  316.  * Name:    format_paragraph
  317.  * Purpose: format paragraph using left, right, and paragraph margins.
  318.  * Date:    November 27, 1991
  319.  * Passed:  window:  pointer to current window
  320.  */
  321. int  format_paragraph( WINDOW *window )
  322. {
  323. register int len;       /* length of current line */
  324. int  first_line;        /* boolean, first line formatted? */
  325. int  spaces;            /* no. of spaces to add */
  326. line_list_ptr p;        /* scratch pointers */
  327. line_list_ptr pp;
  328. char *source;           /* scratch line buffer pointers */
  329. char *dest;
  330. int  rcol;              /* scratch cols and margins */
  331. int  lm;
  332. int  rm;
  333. int  pm;
  334. int  margin;
  335. int  eop;               /* boolean, (e)nd (o)f (p)aragraph? */
  336. int  old_ww;            /* save state of word wrap flag */
  337. long rline;
  338. WINDOW w;               /* scratch window */
  339.  
  340.    if (window->ll->len == EOF)
  341.       return( ERROR );
  342.    entab_linebuff( );
  343.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  344.       return( ERROR );
  345.    if (!is_line_blank( window->ll->line, window->ll->len )) {
  346.       old_ww = mode.word_wrap;
  347.       if (old_ww == NO_WRAP)
  348.          mode.word_wrap = FIXED_WRAP;
  349.       dup_window_info( &w, window );
  350.       g_status.screen_display = FALSE;
  351.  
  352.       /*
  353.        * find the beginning of the paragraph.
  354.        */
  355.       p = w.ll->prev;
  356.       if (g_status.command == FormatParagraph) {
  357.          while (p != NULL &&  !is_line_blank( p->line, p->len )) {
  358.             --w.rline;
  359.             w.ll = w.ll->prev;
  360.             p = p->prev;
  361.          }
  362.          pm = mode.parg_margin;
  363.  
  364.       /*
  365.        * if format text, don't find the beginning of the paragraph.
  366.        *  but we need to know if this is the first line in a paragraph.
  367.        */
  368.       } else if (g_status.command == FormatText) {
  369.          if (p == NULL || is_line_blank( p->line, p->len ))
  370.             pm = mode.parg_margin;
  371.          else
  372.             pm = mode.left_margin;
  373.       } else
  374.          pm = mode.left_margin;
  375.  
  376.       g_status.command = WordWrap;
  377.       p = w.ll;
  378.       if (mode.word_wrap == FIXED_WRAP)
  379.          lm = mode.left_margin;
  380.       else
  381.          lm = pm = find_left_margin( p, mode.word_wrap );
  382.       rm = mode.right_margin;
  383.       eop = FALSE;
  384.  
  385.       /*
  386.        * do the paragraph
  387.        */
  388.       for (first_line=TRUE; p != NULL  &&  !is_line_blank( p->line, p->len ) &&
  389.                             eop == FALSE  &&  !g_status.control_break;) {
  390.  
  391.          /*
  392.           * find out what margin to use
  393.           */
  394.          if (first_line) {
  395.             margin = pm;
  396.             first_line = FALSE;
  397.          } else
  398.             margin = lm;
  399.  
  400.          /*
  401.           * line up the margin
  402.           */
  403.          w.ll->dirty = TRUE;
  404.          copy_line( w.ll );
  405.          detab_linebuff( );
  406.          remove_spaces( 0 );
  407.          rcol = find_word( (text_ptr)g_status.line_buff,
  408.                                      g_status.line_buff_len, 0 );
  409.          if (rcol != ERROR && rcol != margin) {
  410.  
  411.             /*
  412.              * must add spaces to get the indentation right
  413.              */
  414.             if (rcol < margin) {
  415.                source = g_status.line_buff;
  416.                spaces = margin - rcol;
  417.                dest = source + spaces;
  418.  
  419.                assert( g_status.line_buff_len >= 0 );
  420.                assert( g_status.line_buff_len < MAX_LINE_LENGTH );
  421.  
  422.                memmove( dest, source, g_status.line_buff_len );
  423.                g_status.line_buff_len += spaces;
  424.                while (spaces--)
  425.                   *source++ = ' ';
  426.             } else {
  427.                w.rcol = margin;
  428.                word_delete( &w );
  429.                entab_linebuff( );
  430.                un_copy_line( p, &w, TRUE );
  431.                copy_line( w.ll );
  432.                detab_linebuff( );
  433.                remove_spaces( margin );
  434.             }
  435.          }
  436.  
  437.          /*
  438.           * now make sure rest of line is formatted
  439.           */
  440.  
  441.          source = g_status.line_buff;
  442.          len = g_status.line_buff_len;
  443.          for (; len < rm+1 && eop == FALSE;) {
  444.             pp = p->next;
  445.             if (is_line_blank( pp->line, pp->len ))
  446.                eop = TRUE;
  447.             else {
  448.                w.ll = p;
  449.                w.rcol = len + 1;
  450.                if (*(p->line+len-1) == '.')
  451.                   ++w.rcol;
  452.                word_delete( &w );
  453.                entab_linebuff( );
  454.                un_copy_line( p, &w, TRUE );
  455.                copy_line( p );
  456.                detab_linebuff( );
  457.                remove_spaces( margin );
  458.                len = g_status.line_buff_len;
  459.             }
  460.          }
  461.          if (len <= rm+1) {
  462.             entab_linebuff( );
  463.             un_copy_line( p, &w, TRUE );
  464.             p = p->next;
  465.             if (is_line_blank( p->line, p->len ))
  466.                eop = TRUE;
  467.             else {
  468.                w.ll = w.ll->next;
  469.                w.rline++;
  470.             }
  471.          } else {
  472.             w.rcol = rm;
  473.             g_status.key_pressed = *(w.ll->line + rm);
  474.             rline = w.rline;
  475.             word_wrap( &w );
  476.             if (rline == w.rline) {
  477.                w.ll = w.ll->next;
  478.                ++w.rline;
  479.             }
  480.          }
  481.          g_status.copied = FALSE;
  482.          p = w.ll;
  483.       }
  484.       mode.word_wrap = old_ww;
  485.       g_status.copied = FALSE;
  486.       w.file_info->dirty = GLOBAL;
  487.       g_status.screen_display = TRUE;
  488.    }
  489.    return( OK );
  490. }
  491.  
  492.  
  493. /*
  494.  * Name:    combine_wrap_spill
  495.  * Purpose: combine word wrap lines so we don't push each word onto a
  496.  *          separate line.
  497.  * Date:    November 27, 1991
  498.  * Passed:  window:   pointer to current window
  499.  *          wrap_col: col to combine next line
  500.  *          lm:       left margin
  501.  *          rm:       right margin
  502.  *          side:     left or right margin to insert spaces
  503.  *          new_line: boolean, should we insert a new line?
  504.  */
  505. void combine_wrap_spill( WINDOW *window, int wrap_col, int lm, int rm,
  506.                          int side, int new_line )
  507. {
  508. line_list_ptr p;        /* line we wrapped */
  509. line_list_ptr pp;       /* pointer to next line after wrapped line */
  510. int  p_len;             /* length of line we just word wrapped */
  511. int  non_blank;         /* first non-blank column on next line */
  512. int  control_t;         /* number of times to call word_delete */
  513. int  next_line_len;     /* length of next line counting from 1st word */
  514. WINDOW w;               /* scratch window */
  515.  
  516.    dup_window_info( &w, window );
  517.    g_status.command = WordWrap;
  518.    w.rcol = wrap_col;
  519.    if (new_line) {
  520.       insert_newline( &w );
  521.       if (mode.right_justify == TRUE)
  522.          justify_right_margin( &w, w.ll->prev, mode.word_wrap == FIXED_WRAP ?
  523.                 find_left_margin( w.ll->prev, mode.word_wrap ) : lm, rm, side );
  524.       p = window->ll->next;
  525.    } else
  526.       p = window->ll;
  527.    if (p != NULL) {
  528.       p_len = find_end( p->line, p->len );
  529.       pp = p->next;
  530.       if (pp != NULL) {
  531.          non_blank = first_non_blank( pp->line, pp->len );
  532.          next_line_len = find_end( pp->line, pp->len ) - non_blank;
  533.          if (!is_line_blank( pp->line, pp->len ) && p_len + next_line_len <= rm) {
  534.             control_t = 1;
  535.             if (mode.inflate_tabs) {
  536.                if (*pp->line == ' '  ||  *pp->line == '\t')
  537.                   ++control_t;
  538.             } else if (*pp->line == ' ')
  539.                ++control_t;
  540.             w.ll = p;
  541.             w.rcol = p_len + 1;
  542.             if (*(p->line+p_len-1) == '.')
  543.                ++w.rcol;
  544.             while (control_t--)
  545.                word_delete( &w );
  546.             remove_spaces( lm );
  547.             un_copy_line( w.ll, &w, TRUE );
  548.          }
  549.          window->file_info->dirty = GLOBAL;
  550.       }
  551.    }
  552. }
  553.  
  554.  
  555. /*
  556.  * Name:    justify_right_margin
  557.  * Purpose: distribute blanks in line to justify right margin
  558.  * Date:    December 30, 1992
  559.  * Passed:  window:   pointer to current window
  560.  *          ll:       current node pointing to current line
  561.  *          lm:       left margin
  562.  *          rm:       right margin
  563.  *          side:     which side to start inserting space? LEFT or RIGHT
  564.  * Notes:   this routine is based on the spread function by
  565.  *           Kernighan and Plauger in _Software Tools_, Addison-Wesly,
  566.  *           Reading, Mass., 1976, ISBN 0-201-03669-X, pp 240-241.
  567.  */
  568. void justify_right_margin( WINDOW *window, line_list_ptr ll, int lm, int rm,
  569.                            int side )
  570. {
  571. int  len;
  572. int  i;
  573. int  word_count;
  574. int  holes;
  575. int  nb;
  576. int  spaces;
  577. text_ptr s;
  578.  
  579.    /*
  580.     * make sure line is longer than the left margin and less than the right.
  581.     */
  582.    len = find_end( ll->line, ll->len );
  583.    if (len <= lm || len >= rm+1)
  584.       return;
  585.  
  586.    /*
  587.     * now, count the number of words in line.
  588.     */
  589.    i = entab_adjust_rcol( ll->line, ll->len, lm );
  590.    s = ll->line + i;
  591.    len -= i;
  592.    word_count = 0;
  593.    while (len > 0) {
  594.       while (len-- > 0  &&  *s++ == ' ');
  595.       if (len == 0)
  596.          break;
  597.       ++word_count;
  598.       while (len-- > 0  &&  *s++ != ' ');
  599.    }
  600.  
  601.    /*
  602.     * can't justify right margin with one word or less.
  603.     */
  604.    if (word_count <= 1)
  605.       return;
  606.  
  607.    holes = word_count - 1;
  608.    copy_line( ll );
  609.    detab_linebuff( );
  610.    remove_spaces( lm );
  611.  
  612.    /*
  613.     * find out how many spaces we need.  if spaces <= 0, then get out.
  614.     */
  615.    i = g_status.line_buff_len - 1;
  616.    spaces = rm - i;
  617.    if (spaces <= 0)
  618.       return;
  619.    g_status.line_buff_len += spaces;
  620.  
  621.    /*
  622.     * this while loop is based on the while loop on page 241 in
  623.     *   _Software Tools_, Kernighan and Plauger.  I added a while loop
  624.     *   to skip extra blanks after a period or other space intentially
  625.     *   inserted into the text.
  626.     */
  627.    while (i < rm) {
  628.       g_status.line_buff[rm] = g_status.line_buff[i];
  629.       if (g_status.line_buff[rm] == ' ') {
  630.  
  631.          /*
  632.           * this while loop copies extra blanks after a period or
  633.           *   blanks otherwise intentially left in the text.
  634.           */
  635.          while (g_status.line_buff[i-1] == ' ')
  636.             g_status.line_buff[--rm] = g_status.line_buff[--i];
  637.  
  638.          nb = side == LEFT ? spaces / holes : (spaces - 1) / holes + 1;
  639.          spaces -= nb;
  640.          --holes;
  641.          while (nb-- > 0)
  642.             g_status.line_buff[--rm] = ' ';
  643.       }
  644.       --i;
  645.       --rm;
  646.    }
  647.    entab_linebuff( );
  648.    un_copy_line( ll, window, window->bottom_line );
  649. }
  650.  
  651.  
  652. /*
  653.  * Name:    remove_spaces
  654.  * Purpose: remove any extra spaces in the text
  655.  * Date:    December 30, 1992
  656.  * Passed:  lm:   left margin
  657.  * Notes:   this routine squeezes out extra space from a previous format.
  658.  *          the line must be placed in the line buffer before calling this
  659.  *            function.
  660.  */
  661. void remove_spaces( int lm )
  662. {
  663. int  period;
  664. int  len;
  665. int  i;
  666. int  c;
  667. char *s;
  668. char *d;
  669.  
  670.    if ((i = len = g_status.line_buff_len) <= lm)
  671.       return;
  672.  
  673.    period = FALSE;
  674.    s = d = g_status.line_buff + lm;
  675.    i -= lm;
  676.    c = (int)*s++;
  677.    while (c == ' ' && i > 0) {
  678.       c = *s++;
  679.       --i;
  680.       --len;
  681.    }
  682.    period = c == '.' ? TRUE : FALSE;
  683.    while (i > 0) {
  684.       *d++ = (char)c;
  685.       c = (int)*s++;
  686.       --i;
  687.       if (c != ' ')
  688.          period =  c == '.' ? TRUE : FALSE;
  689.       else {
  690.          *d++ = (char)c;
  691.          c = (int)*s++;
  692.          --i;
  693.          if (period  &&  c == ' ') {
  694.             *d++ = (char)c;
  695.             period = FALSE;
  696.             if (i > 0)
  697.                ++len;
  698.          }
  699.          while (c == ' '  &&  i > 0) {
  700.             c = (int)*s++;
  701.             --len;
  702.             --i;
  703.          }
  704.       }
  705.    }
  706.    *d = (char)c;
  707.    g_status.line_buff_len = len;
  708. }
  709.  
  710.  
  711. /*
  712.  * Name:    find_word
  713.  * Purpose: find a word on a line
  714.  * Date:    November 29, 1991
  715.  * Passed:  p:          pointer to a line of text
  716.  *          len:        len of line
  717.  *          start_col:  col to start the search
  718.  * Notes:   returns the column of the next word or -1 (ERROR) if no more words
  719.  */
  720. int  find_word( text_ptr p, int len, int start_col )
  721. {
  722. register int rc;
  723. register char c;
  724.  
  725.    if (len <= start_col  ||  len < 0  || start_col < 0)
  726.       return( ERROR );
  727.    p += start_col;
  728.    rc = start_col;
  729.  
  730.    if (mode.inflate_tabs) {
  731.       while (len-- > 0 && ((c = *p++) == ' ' || c == '\t'))
  732.          if (c != '\t')
  733.             ++rc;
  734.          else
  735.             rc += mode.ptab_size - (rc % mode.ptab_size);
  736.    } else
  737.       while (len-- > 0  &&  (c = *p++) == ' ')
  738.          ++rc;
  739.    if (len <= 0)
  740.      rc = ERROR;
  741.    return( rc );
  742. }
  743.  
  744.  
  745. /*
  746.  * Name:    flush_left
  747.  * Purpose: flush line on left margin
  748.  * Date:    November 27, 1991
  749.  * Passed:  window:  pointer to current window
  750.  */
  751. int  flush_left( WINDOW *window )
  752. {
  753. int  len;       /* length of current line */
  754. register int spaces;
  755. char *source;
  756. char *dest;
  757. int  rcol;
  758. int  lm;
  759. register WINDOW *win;          /* put window pointer in a register */
  760.  
  761.    win = window;
  762.    copy_line( win->ll );
  763.    detab_linebuff( );
  764.    lm = mode.left_margin;
  765.    rcol = find_word( (text_ptr)g_status.line_buff, g_status.line_buff_len, 0 );
  766.    if (rcol != ERROR && rcol != lm) {
  767.  
  768.       /*
  769.        * must add spaces to get the indentation correct
  770.        */
  771.       if (rcol < lm) {
  772.          source = g_status.line_buff;
  773.          spaces = lm - rcol;
  774.          dest = source + spaces;
  775.          len = g_status.line_buff_len;
  776.          if (len + spaces > MAX_LINE_LENGTH) {
  777.             /*
  778.              * line would be too long
  779.              */
  780.             error( WARNING, win->bottom_line, ww1 );
  781.             return( ERROR );
  782.          } else {
  783.             load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  784.  
  785.             assert( len >= 0 );
  786.             assert( len < MAX_LINE_LENGTH );
  787.  
  788.             memmove( dest, source, len );
  789.             g_status.line_buff_len += spaces;
  790.             while (spaces--)
  791.                *source++ = ' ';
  792.             win->file_info->dirty = GLOBAL;
  793.          }
  794.  
  795.       /*
  796.        * else delete spaces to get the indentation correct
  797.        */
  798.       } else {
  799.          dest = g_status.line_buff + lm;
  800.          source = g_status.line_buff + rcol;
  801.  
  802.          assert( g_status.line_buff_len - rcol >= 0 );
  803.          assert( g_status.line_buff_len - rcol < MAX_LINE_LENGTH );
  804.  
  805.          memmove( dest, source, g_status.line_buff_len - rcol );
  806.          g_status.line_buff_len -= (rcol - lm);
  807.          win->file_info->dirty = GLOBAL;
  808.       }
  809.       win->ll->dirty = TRUE;
  810.       show_changed_line( win );
  811.    }
  812.    return( OK );
  813. }
  814.  
  815.  
  816. /*
  817.  * Name:    flush_right
  818.  * Purpose: flush line on right margin
  819.  * Date:    November 27, 1991
  820.  * Passed:  window:  pointer to current window
  821.  */
  822. int  flush_right( WINDOW *window )
  823. {
  824. int  len;               /* length of current line */
  825. int  i;
  826. int  spaces;
  827. char *source;
  828. char *dest;
  829. register int rcol;
  830. int  rm;
  831. register WINDOW *win;   /* put window pointer in a register */
  832.  
  833.    win = window;
  834.    copy_line( win->ll );
  835.    detab_linebuff( );
  836.    source = g_status.line_buff;
  837.    len = g_status.line_buff_len;
  838.    if (!is_line_blank( (text_ptr)source, len )) {
  839.       rm = mode.right_margin;
  840.       for (rcol=len-1; rcol>=0 && *(source+rcol) == ' ';)
  841.          rcol--;
  842.       if (rcol != rm) {
  843.  
  844.          /*
  845.           * if rcol is less than right margin then we need to add spaces.
  846.           */
  847.          if (rcol < rm) {
  848.             spaces = rm - rcol;
  849.             dest = source + spaces;
  850.             if (len + spaces > MAX_LINE_LENGTH) {
  851.                /*
  852.                 * line would be too long
  853.                 */
  854.                error( WARNING, win->bottom_line, ww1 );
  855.                return( ERROR );
  856.             } else {
  857.                load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  858.  
  859.                assert( len >= 0 );
  860.                assert( len < MAX_LINE_LENGTH );
  861.  
  862.                memmove( dest, source, len );
  863.                g_status.line_buff_len += spaces;
  864.                while (spaces--)
  865.                   *source++ = ' ';
  866.                win->file_info->dirty = GLOBAL;
  867.             }
  868.  
  869.          /*
  870.           * if rcol is greater than right margin then we need to sub spaces.
  871.           */
  872.          } else {
  873.             load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  874.             rcol = rcol - rm;
  875.             i = first_non_blank( (text_ptr)source, len );
  876.             if (rcol > i)
  877.                rcol = i;
  878.             dest = source + rcol;
  879.  
  880.             assert( len - rcol >= 0 );
  881.             assert( len - rcol < MAX_LINE_LENGTH );
  882.  
  883.             memmove( source, dest, len - rcol );
  884.             g_status.line_buff_len -= (rcol - rm);
  885.             win->file_info->dirty = GLOBAL;
  886.          }
  887.          win->ll->dirty = TRUE;
  888.          show_changed_line( win );
  889.       }
  890.    }
  891.    return( OK );
  892. }
  893.  
  894.  
  895. /*
  896.  * Name:    flush_center
  897.  * Purpose: flush line in center of margins
  898.  * Date:    November 27, 1991
  899.  * Passed:  window:  pointer to current window
  900.  */
  901. int  flush_center( WINDOW *window )
  902. {
  903. int  len;               /* length of current line */
  904. char *source;           /* temp line buffer pointers */
  905. char *dest;
  906. int  rm;
  907. int  lm;
  908. register int spaces;    /* center of text on current line */
  909. int  center;            /* center of current margins */
  910. int  first;             /* column of first char on line */
  911. int  last;              /* column of last char on line */
  912. register WINDOW *win;   /* put window pointer in a register */
  913.  
  914.    win = window;
  915.    copy_line( win->ll );
  916.    detab_linebuff( );
  917.    source = g_status.line_buff;
  918.    len = g_status.line_buff_len;
  919.    if (!is_line_blank( (text_ptr)source, len )) {
  920.       rm = mode.right_margin;
  921.       lm = mode.left_margin;
  922.       center = (rm + lm) / 2;
  923.       first = first_non_blank( (text_ptr)source, len );
  924.       for (last=len-1; last>=0 && *(source+last) == ' ';)
  925.          last--;
  926.       spaces = last + first - 1;
  927.       spaces = (spaces / 2) + (spaces & 1);
  928.       if (spaces != center) {
  929.  
  930.          /*
  931.           * if spaces is less than center margin then we need to add spaces.
  932.           */
  933.          if (spaces < center) {
  934.             spaces = center - spaces;
  935.             dest = source + spaces;
  936.             if (len + spaces > MAX_LINE_LENGTH) {
  937.                /*
  938.                 * line would be too long
  939.                 */
  940.                error( WARNING, win->bottom_line, ww1 );
  941.                return( ERROR );
  942.             } else {
  943.                load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  944.  
  945.                assert( len >= 0 );
  946.                assert( len < MAX_LINE_LENGTH );
  947.  
  948.                memmove( dest, source, len );
  949.                g_status.line_buff_len += spaces;
  950.                while (spaces--)
  951.                   *source++ = ' ';
  952.                win->file_info->dirty = GLOBAL;
  953.             }
  954.  
  955.          /*
  956.           * if spaces is greater than center margin then we need to sub spaces.
  957.           */
  958.          } else {
  959.             load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  960.             spaces = spaces - center;
  961.             if (spaces > first)
  962.                spaces = first;
  963.             dest = source + spaces;
  964.  
  965.             assert( len - spaces >= 0 );
  966.             assert( len - spaces < MAX_LINE_LENGTH );
  967.  
  968.             memmove( source, dest, len - spaces );
  969.             g_status.line_buff_len -= spaces;
  970.             win->file_info->dirty = GLOBAL;
  971.          }
  972.          win->ll->dirty = TRUE;
  973.          show_changed_line( win );
  974.       }
  975.    }
  976.    return( OK );
  977. }
  978.